package protoctl

import (
	"context"
	"errors"
	"net/http"
	"time"

	"gitee.com/lcc_dr/restful-api-demo/apps"
	restfulspec "github.com/emicklei/go-restful-openapi/v2"
	"github.com/emicklei/go-restful/v3"
	"github.com/go-openapi/spec"
	"github.com/infraboard/mcube/logger"
	"github.com/infraboard/mcube/logger/zap"
)

type RestServer struct {
	srv     *http.Server
	log     logger.Logger
	restcon *restful.Container
}

func (h *RestServer) Start() error {

	config := restfulspec.Config{
		WebServices:                   restful.RegisteredWebServices(), // you control what services are visible
		APIPath:                       "/apidocs.json",
		PostBuildSwaggerObjectHandler: enrichSwaggerObject,
	}

	h.restcon.Add(restfulspec.NewOpenAPIService(config))
	// restful.DefaultContainer.Add(restfulspec.NewOpenAPIService(config))

	// Optionally, you can install the Swagger Service which provides a nice Web UI on your REST API
	// You need to download the Swagger HTML5 assets and change the FilePath location in the config below.
	// Open http://localhost:8080/apidocs/?url=http://localhost:8080/apidocs.json
	http.Handle("/apidocs/", http.StripPrefix("/apidocs/", http.FileServer(http.Dir("/Users/emicklei/Projects/swagger-ui/dist"))))

	// Optionally, you may need to enable CORS for the UI to work.
	cors := restful.CrossOriginResourceSharing{
		AllowedHeaders: []string{"Content-Type", "Accept"},
		AllowedMethods: []string{"GET", "POST", "PUT", "DELETE"},
		CookiesAllowed: false,
		Container:      restful.DefaultContainer}
	restful.DefaultContainer.Filter(cors.Filter)

	h.log.Info("Get the API using http://localhost:8080/apidocs.json")

	h.log.Info("Open Swagger UI using http://localhost:8080/apidocs/?url=http://localhost:8080/apidocs.json")
	if err := h.srv.ListenAndServe(); err != nil {

		if errors.Is(err, http.ErrServerClosed) {
			h.log.Info("stop restful-HttpServer Success")

		} else {
			h.log.Errorf("Failed to listen and restful-HttpServer,error: %v", err)

			return err

		}

	}
	return nil
}

func (h *RestServer) Stop() error {

	h.log.Info("restful-httpServer exiting")
	ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
	defer cancel()

	if err := h.srv.Shutdown(ctx); err != nil {
		h.log.Errorf("Server forced to shutdown:", err)
	}

	return nil

}

func NewRestServer() *RestServer {

	con := restful.DefaultContainer
	apps.InitRestful(con)
	// addr := fmt.Sprintf("%s:%s", conf.GetConf().App.Host, conf.GetConf().App.Port)
	addr := ":8080"
	srv := &http.Server{
		Addr:              addr,
		Handler:           con,
		ReadHeaderTimeout: 60 * time.Second,
		ReadTimeout:       60 * time.Second,
		WriteTimeout:      60 * time.Second,
		IdleTimeout:       60 * time.Second,
		MaxHeaderBytes:    1 << 20, // 1M

	}
	return &RestServer{
		restcon: con,
		log:     zap.L().Named("restful-http-server"),
		srv:     srv,
	}

}

func enrichSwaggerObject(swo *spec.Swagger) {
	swo.Info = &spec.Info{
		InfoProps: spec.InfoProps{
			Title:       "UserService",
			Description: "Resource for managing Users",
			Contact: &spec.ContactInfo{
				ContactInfoProps: spec.ContactInfoProps{
					Name:  "john",
					Email: "john@doe.rp",
					URL:   "http://johndoe.org",
				},
			},
			License: &spec.License{
				LicenseProps: spec.LicenseProps{
					Name: "MIT",
					URL:  "http://mit.org",
				},
			},
			Version: "1.0.0",
		},
	}
	swo.Tags = []spec.Tag{spec.Tag{TagProps: spec.TagProps{
		Name:        "users",
		Description: "Managing users"}}}
}
